use std::collections::HashMap;
use std::sync::Arc;

use im::{Vector};

use crate::attrs::Attrs;
use crate::fragment::Fragment;
use crate::mark::Mark;
/**
 * 基础节点定义 任何数据都可以认为是节点
 * @property id 节点id
 * @property type 节点类型
 * @property attrs 节点属性 一般用于元数据的存储
 * @property content 子节点
 * @property marks 节点标记
 * @author string<348040933@qq.com>
 */
#[derive(Debug, Clone, PartialEq)]
pub struct Node {
    pub id: String,
    pub r#type: String,
    pub attrs: Attrs,
    pub content: Arc<Fragment>,
    pub marks: Vector<Mark>,
}
unsafe impl Send for Node {}
unsafe impl Sync for Node {}

impl Node {
    pub fn new(
        id: String,
        r#type: String,
        attrs: Attrs,
        content: Fragment,
        marks: Vec<Mark>,
    ) -> Self {
        Node {
            id,
            r#type,
            attrs: attrs,
            content: Arc::new(content),
            marks: marks.into(),
        }
    }
    pub fn node_at(&self, id: &String) -> Option<Node> {
        if id == &self.id {
            return Some(self.clone());
        }
        return self.content.node_at(id);
    }
    pub fn child_count(&self) -> usize {
        self.content.child_count()
    }

    pub fn set_attrs(
        doc: &mut Node,
        id: &String,
        values: &HashMap<String, serde_json::Value>,
    ) -> Option<Node> {
        if values.len() > 0 {
            return Node::update_by_id(doc, id, move |node| {
                let mut new_node = node.clone();
                for (key, value) in values {
                    new_node.attrs = new_node.attrs.update(key.to_string(), value.clone());
                }
                Some(new_node)
            });
        }
        None
    }

    pub fn remove_marks<F>(doc: &mut Node, id: &String, callback: F) -> Option<Node>
    where
        F: Fn(&&Mark) -> bool,
    {
        return Node::update_by_id(doc, id, |node| {
            //获取到需要的Mark
            let marks: Vector<Mark> = node
                .marks
                .iter()
                .filter(|item| callback(item))
                .map(|f| f.clone())
                .collect();
            if marks.len() > 0 {
                return Some(Node {
                    id: node.id.clone(),
                    r#type: node.r#type.clone(),
                    attrs: node.attrs.clone(),
                    content: node.content.clone(),
                    marks,
                });
            }
            return None;
        });
    }

    pub fn update_by_id<F>(doc: &mut Node, id: &String, callback: F) -> Option<Node>
    where
        F: Fn(&mut Node) -> Option<Node>,
    {
        if doc.id == *id {
            callback(doc)
        } else {
            //判断 子节点 是否存在
            let find_node = doc
                .content
                .content
                .iter()
                .find(|node: &&Arc<Node>| node.id == *id);
            match find_node {
                Some(f_node) => {
                    if let Some(new_node) = callback(&mut f_node.as_ref().clone()) {
                        let index = doc.content.content.index_of(f_node).unwrap();
                        let content = doc.content.content.update(index, Arc::new(new_node));
                        return Some(Node {
                            id: doc.id.clone(),
                            r#type: doc.r#type.clone(),
                            attrs: doc.attrs.clone(),
                            content: Arc::new(Fragment { content }),
                            marks: doc.marks.clone(),
                        });
                    }
                }
                None => {
                    let mut content = None;
                    doc.content.content.iter().for_each(|node: &Arc<Node>| {
                        if let Some(new_node) =
                            Node::update_by_id(&mut node.as_ref().clone(), id, &callback)
                        {
                            let index = doc.content.content.index_of(node).unwrap();
                            content = Some(doc.content.content.update(index, Arc::new(new_node)));
                            return;
                        }
                    });
                    if let Some(content) = content {
                        return Some(Node {
                            id: doc.id.clone(),
                            r#type: doc.r#type.clone(),
                            attrs: doc.attrs.clone(),
                            content: Arc::new(Fragment { content }),
                            marks: doc.marks.clone(),
                        });
                    }
                }
            }
            None
        }
    }
}
